<!--虚拟树组件-->
<template>
    <div>
        <vi-list ref="virtualList" class="large-tree" :itemHeight="lineHeight" :height="height" :data="viewData">
            <template v-slot="{item}">
                <div class="large-tree-item"
                :style="[{background:`${item._GROUND}`},{height:lineHeight+'px'},{lineHeight:lineHeight+'px'}]"
                :class="[`level-${item._LEVEL}`, {'has-child': item._HAS_CHILDREN, 'is-expand': item._EXPAND}]">
                    <div @click="clickTreeNode(item)" class="node-item-div" :style="{paddingLeft: `${item._LEVEL * 20}px`}">
                        <div class="expand-icon" :style="{height:lineHeight+'px'}">
                            <div class="icon-pa">
                                <div class="caret-right"></div>
                            </div>
                        </div>
                        <div class="tree-item-pa">
                            <vi-check-box v-show="checkBox"
                            @change="checkboxOnclick(item)" 
                            :indeterminate="item._INDETERMINATE" 
                             v-model="item._CHECK" 
                            class="check"></vi-check-box>
                            <div class="tree-item-ch">
                                <slot :item="item">
                                    {{ item[label] }}
                                </slot>
                            </div>
                        </div>
                    </div>
                </div>
            </template>
        </vi-list>
    </div>
</template>
<script>
import ViCheckBox from '../packages/components/vi-check-box.vue'
import ViList from '../packages/list/src/vi-list.vue'
import treeUtils from '../utils/treeUtils'

export default {
    components:{ViCheckBox, ViList},
    name: 'vi-tree',
    props: {
        //数据
        data:{
            type:Array,
            require:true
        },
        //子节点属性
        children:{
            type:String,
            default:'children'
        },
        //指定节点标签为节点对象的某个属性值
        label:{
            type:String,
            default:'label'
        },
        //节点的唯一标识
        itemKey:{
            type:String,
            default:'id'
        },
        //高度
        height:{
            type:Number,
            default:300
        },
        lineHeight:{
            type:Number,
            default:26
        },
        //默认全部展开
        expand:{
            type:Boolean,
            default:false
        },
        //开启复选功能
        checkBox:{
            type:Boolean,
            default:false
        },
        //默认展开节点
        expandData:{
            type:Array,
            default:()=> []
        },
        //自定义搜索方法
        filterMethod:{
            type:Function,
            default:function (val,item){
                // eslint-disable-next-line vue/no-deprecated-props-default-this
                if(!item[this.label]){
                    return false
                }
                // eslint-disable-next-line vue/no-deprecated-props-default-this
                return item[this.label].indexOf(val)!=-1
            }
        }

    },
    data() {
        return {
            loading:false,

            treeData:null,
            treeDataCopy:null,
            viewData:[],

            checkBoxData:null,

            filterValue:null,

            fullList:0
        }
    },

    watch:{
        data:{
            deep:true,
            handler(){
                this.loadTree()
            }
        },

        expandData:{
            deep:true,
            handler(){
                this.manualExpand()
            }
        },

        expand:{
            handler(){
                if(this.expand){
                    treeUtils.eachTree(this.treeData,item=>{
                        item._VISIBLE=true
                        item._EXPAND=item._HAS_CHILDREN
                    },{children:this.children})
                }else{
                    treeUtils.eachTree(this.treeData,item=>{
                        item._VISIBLE = !item._LEVEL
                        item._EXPAND = false
                    },{children:this.children})
                }
                this.refreshTree()
            }
        }
    },

    created(){
        this.loadTree()
    },

    methods:{

        loadTree(){
            this.loading=true
            setTimeout(()=>{
                // let startTime=Date.now()
                // if(!this.data||this.data.length==0){
                //     return
                // }
                let i=0
                this.treeData=JSON.parse(JSON.stringify(this.data))
                const data=this.treeData
                treeUtils.eachTree(data,(item,index,items,paths,parent,nodes)=>{
                    item._LEVEL = nodes.length-1
                    item._EXPAND = false
                    item._GROUND = "white"
                    item._CHECK = false
                    item._INDETERMINATE = false	
                    item._VISIBLE = !item._LEVEL
                    item._KEY = i++
                    //关闭循环引用
                    // if(this.circularReference){
                    //     item._PARENT = parent
                    // }
                    item._HAS_CHILDREN = item[this.children] && item[this.children].length>0
                    item._IS_LEAF = !item._HAS_CHILDREN
                    if(item._LEVEL>0){
                        item._PARENT_ID=parent[this.itemKey]
                    }
                    if(this.checkBox){
                        item._PATHS=paths
                    }
                },{children: this.children})
                this.treeDataCopy=JSON.parse(JSON.stringify(data))
                if(this.expand){
                    treeUtils.eachTree(this.treeData,item=>{
                        item._VISIBLE=true
                        item._EXPAND=item._HAS_CHILDREN
                    },{children:this.children})
                }
                if(this.expandData.length){
                    this.defaultExpand()
                }
                this.refreshTree()
                // this.$nextTick(()=>{
                //     console.info('渲染行数'+this.fullList,'渲染时间'+(Date.now()-startTime)+'ms')
                // },200)
            },200)
        },

        refreshTree(){
            const treeList=treeUtils.toTreeArray(this.treeData,{children:this.children})
            this.fullList=treeList.length
            this.viewData=treeList.filter(item=>item._VISIBLE)
            this.loading=false
            this.$refs.virtualList.initWrap()
            // console.info("显示结果",this.viewData)
        },

        groundInit(){
            treeUtils.eachTree(this.treeData,item=>{
                item._GROUND='white'
            },{children:this.children})
        },

        clickTreeNode(node){
            this.$emit('click-node',node)
            // this.groundInit()  
            // if(node._HAS_CHILDREN){
            //     let expand=!node._EXPAND
            //     node._EXPAND=expand
            //     treeUtils.eachTree(node[this.children],(item,index,items,paths,parent)=>{
            //     item._VISIBLE = parent? parent._VISIBLE&&parent._EXPAND : expand
            //     },{children:this.children})
            // }
            // this.loading=true
            // node._GROUND='#F0F7FF'
            // this.refreshTree()

            if(!node._HAS_CHILDREN){
                this.groundInit()
                node._GROUND='#F0F7FF'
                return
            }
            let data=[]
            let deleteIndex=0
            let deleteSize=0
            for(let l=this.viewData.length,i=0;i<l;i++){
                let item=this.viewData[i]
                if(item!=node){
                    item._GROUND='white'
                    data.push(item)
                }else{
                    item._GROUND='#F0F7FF'
                    let expand=!item._EXPAND
                    item._EXPAND=expand
                    data.push(item)
                    if(expand){
                        item[this.children].forEach(e=>{
                            e._VISIBLE=true
                            data.push(e)
                        })
                    }else{
                        deleteIndex=i+1
                        treeUtils.eachTree(item[this.children],(item)=>{
                            if(item._VISIBLE){
                                item._VISIBLE=false
                                item._EXPAND=false
                                deleteSize++
                            }
                        },{children:this.children})
                    }
                }
            }
            if(deleteSize>0){
                data.splice(deleteIndex,deleteSize)
            }
            this.viewData=data
            this.$refs.virtualList.initWrap()
        },

        setAllExpand(boolean){
            if(boolean){
                treeUtils.eachTree(this.treeData,item=>{
                    item._VISIBLE=true
                    item._EXPAND=item._HAS_CHILDREN
                },{children:this.children})
            }else{
                treeUtils.eachTree(this.treeData,item=>{
                    item._EXPAND=false
                    item._VISIBLE=!item._LEVEL
                },{children:this.children})
            }
            this.refreshTree()
        },

        checkboxOnclick(node){
            // console.info("点击",node)
            this.$emit('check',node,node._CHECK)
            let check=node._CHECK
            node._INDETERMINATE=false
            treeUtils.eachTree(node[this.children],item=>{
                item._CHECK=check
                item._INDETERMINATE=false
            },{children:this.children})
            if(node._LEVEL!=0){
                if(this.circularReference){
                    this.checkParent(node._PARENT)
                }else{
                    this.checkPaths(node._PATHS)
                }
            }
            this.refreshTree()
        },

        //循环引用关闭
        checkParent(node){
            while(node!=null){
                let checkNum=0
                let indeterminate=0
                node[this.children].forEach(el => {
                    if(el._CHECK){
                        checkNum++
                    }
                    if(el._INDETERMINATE){
                        indeterminate++
                    }
                });
                if(node[this.children]!=null&&node[this.children].length>0){
                    if(indeterminate>0){
                        node._CHECK=false
                        node._INDETERMINATE=true
                    }
                    if(checkNum==node[this.children].length){
                        node._CHECK=true
                        node._INDETERMINATE=false
                    }
                    if(checkNum>0&&checkNum<node[this.children].length){
                        node._CHECK=false
                        node._INDETERMINATE=true
                    }
                    if(checkNum==0&&indeterminate==0){
                        node._CHECK=false
                        node._INDETERMINATE=false
                    }
                }
                node=node._PARENT
            }
        },

        checkPaths(paths){
            for(let a=paths.length-2;a>=1;a--){
                let node=this.treeData
                for(let b=0;b<a;b++){
                    node=node[paths[b]]
                }
                if(!Array.isArray(node)){
                    let checkNum=0
                    let indeterminate=0
                    node[this.children].forEach(el => {
                        if(el._CHECK){
                            checkNum++
                        }
                        if(el._INDETERMINATE){
                            indeterminate++
                        }
                    });
                    if(node[this.children]!=null&&node[this.children].length>0){
                        if(indeterminate>0){
                            node._CHECK=false
                            node._INDETERMINATE=true
                        }
                        if(checkNum==node[this.children].length){
                            node._CHECK=true
                            node._INDETERMINATE=false
                        }
                        if(checkNum>0&&checkNum<node[this.children].length){
                            node._CHECK=false
                            node._INDETERMINATE=true
                        }
                        if(checkNum==0&&indeterminate==0){
                            node._CHECK=false
                            node._INDETERMINATE=false
                        }
                    }
                }
            }
        },

        //手动展开expandData
        manualExpand(){
            this.defaultExpand()
            this.refreshTree()
        },

        //展开指定路径
        expandPaths(paths){
            this.setShowNode(paths)
            this.refreshTree()
        },        

        defaultExpand(){
            if(this.expandData&&this.expandData.length>0){
                this.expandData.forEach(id=>{
                    treeUtils.eachTree(this.treeData,(item,index,items,paths)=>{
                        if(id==item[this.itemKey]){
                            this.setShowNode(paths,id)
                        }
                    },{children:this.children})
                })
            }
            
        },

        setShowNode(paths){
            let node=this.treeData
            for(let i=0;i<paths.length;i++){
                node=node[paths[i]]
                if(!Array.isArray(node)){
                    if(node._HAS_CHILDREN&&i!=paths.length-1){
                        node._EXPAND=true
                    }
                    node._VISIBLE=true
                }else{
                    node.forEach(e=>{
                        e._VISIBLE=true
                    })
                }
            }
        },

        //获得复选框选择性（包括半选中状态）
        getIndeterminate(){
            const treeList=treeUtils.toTreeArray(this.treeData,{children:this.children})
            return this.checkBoxData=treeList.filter(item=>item._CHECK||item._INDETERMINATE)
        },

        //获得复选框选择项
        getCheckNode(){
            this.checkBoxData=null
            const treeList=treeUtils.toTreeArray(this.treeData,{children:this.children})
            this.checkBoxData=treeList.filter(item=>item._CHECK)
            return this.checkBoxData
        },

        //默认过滤
        filter(val){
            this.treeData=JSON.parse(JSON.stringify(this.treeDataCopy))
            if(val){
                // let startTime=Date.now()
                let result=new Map()
                treeUtils.eachTree(this.treeData,(item,index,items,paths)=>{
                    if(this.filterMethod(val,item)){
                        let node=this.treeData
                        for(let i=0;i<paths.length;i++){
                            node=node[paths[i]]
                            if(!Array.isArray(node)){
                                if(node._HAS_CHILDREN){
                                    node._EXPAND=true
                                }
                                node._VISIBLE=true
                                if(!result.has(node["_KEY"])){
                                    result.set(node["_KEY"],node)
                                }
                            }
                        }
                        item._EXPAND=false
                    }
                },{children:this.children})
                let source=[]
                for(var value of result.values()){
                    if(value._LEVEL==0){
                        source.push(value)
                    }
                }
                this.treeData=source
                // console.info("过滤时间"+(Date.now()-startTime)+'ms')
            }
            this.refreshTree()
        },

        // toArrayTree(data,children,key){
        //     for(let i=0,len=data.length;i<len;i++){
        //         let parent=data[i]._PARENT
        //         if(parent==null){
        //             continue
        //         }
        //         if(parent.children==null){
        //             parent.children=[]
        //         }
        //         parent.children.push(data[i])
        //     } 
        // },

        //获得显示的节点
        getExpandNode(){
            return this.viewData
        }

    }
}
</script>
<style>
    .check{
        margin-right:5px;
        margin-top: 6.5px;
    }
    .large-tree {
        padding: 0;
        background-color: #fff;
    }
    .node-item-div{
        display: flex;
    }
    .node-item-div:hover {
        background:#F5F7FA;
    }
    .tree-item-pa{
        display: flex;
        color:#303133;
        cursor:pointer;
    }
    .tree-item-ch{
        white-space: nowrap;
    }
    .expand-icon{
        width: 9px;
        padding-left: 3px;
    }
    .icon-pa{
        position: relative;
        top: calc(50% - 4px);
        width: 4px;
        height: 8px;
        visibility: hidden;
    }
    .caret-right{
        width: 0;
        height: 0;
        border: 4px solid transparent;
        border-left: 4px solid #909399;
        
    }
    .large-tree .large-tree-item.has-child .icon-pa {
        visibility: visible;
        transition: all 0.3s;
    }
    .large-tree .large-tree-item.is-expand .icon-pa {
        transform: rotate(90deg);
    }
</style>